#include "BackupFSBitmap.h"
#include "BackupFSDefines.h"
namespace BackupFS
{
	BackupFSBit::BackupFSBit(LONGLONG index):
		_Index(index)
	{
	}
	BackupFSBit::~BackupFSBit()
	{

	}
	bool BackupFSBit::IsSet(LONGLONG offset)const
	{
		if (offset < 0 || offset >= BACKUPFS_BITMAP_SIZE * BACKUPFS_PAGE_SIZE)
		{
			return false;
		}
		LONGLONG index = offset / BACKUPFS_PAGE_SIZE;
		return _Bits.test(index);
	}
	void BackupFSBit::Set(LONGLONG offset, LONGLONG length)
	{
		if (offset < 0)
		{
			return;
		}
		LONGLONG start_bit = offset / BACKUPFS_PAGE_SIZE;
		LONGLONG end_bit = (offset + length + BACKUPFS_PAGE_SIZE - 1) / BACKUPFS_PAGE_SIZE;

		for (LONGLONG i = start_bit; i < end_bit; i++)
		{
			_Bits.set(i);
		}
	}
	BackupFSBitmap::BackupFSBitmap(const std::wstring& DataPath, bool SaveToFile,LONGLONG Index, LONGLONG BlockSize/* = BACKUPFS_PAGE_SIZE*/)
	{
		_Index = Index;
		_BlockSize = BlockSize;
		_Length = BACKUPFS_BITMAP_GROUP_SIZE / _BlockSize / 8;
		_Data.resize(_Length, 0);
		_Path = DataPath;
		_SaveToFile = SaveToFile;
		if (_SaveToFile)
		{
			_OpenFiles();
		}
	}
	BackupFSBitmap::~BackupFSBitmap()
	{
		
		if (_MapView)
		{
			UnmapViewOfFile(_MapView);
			_MapView = nullptr;
		}
		if (_MappingFile != INVALID_HANDLE_VALUE)
		{
			CloseHandle(_MappingFile);
			_MappingFile = INVALID_HANDLE_VALUE;
		}
		if (_File != INVALID_HANDLE_VALUE)
		{
			CloseHandle(_File);
			_File = INVALID_HANDLE_VALUE;
		}
		
	}
	/*
	use filemapping to save the bitamp file for performance
	*/
	void BackupFSBitmap::_OpenFiles()
	{
		std::wstring bitmap_file = _Path + L"\\INC_BITMAP_" + std::to_wstring(_Index) + L".BITMAP";
		_File=CreateFile(bitmap_file.c_str(),
			GENERIC_READ | GENERIC_WRITE,
			0,
			NULL,
			OPEN_ALWAYS,
			FILE_ATTRIBUTE_NORMAL,
			NULL
		);
		_MappingFile = CreateFileMapping(_File,
			NULL,
			PAGE_READWRITE,
			0,
			(DWORD)_Length,
			NULL
		);
		if (_MappingFile >0)
		{
			_MapView = MapViewOfFile(
				_MappingFile,
				FILE_MAP_ALL_ACCESS,
				0,
				0,
				_Length
			);
			if (_MapView)
			{
				memcpy(_Data.data(), _MapView, _Length);
			}
		}
	}
	/*
	Set the bitmap bit to "Used"
	*/
	void BackupFSBitmap::Set(LONGLONG offset, LONGLONG length)
	{
		LONGLONG new_length = (offset + length) / _BlockSize / 8;
		if (new_length > _Length)
		{
			return;
		}
		LONGLONG begin = offset / _BlockSize;
		LONGLONG end = (offset + length - 1) / _BlockSize;
		//for each byte
		for (LONGLONG i = begin; i <= end; i++)
		{
			LONGLONG new_offset = i * _BlockSize;
			LONGLONG bytes = new_offset / (_BlockSize * 8);
			LONGLONG bits = (new_offset % (_BlockSize * 8)) / _BlockSize;
			unsigned char* data = _Data.data();
			data[bytes] |= (0x80 >> bits);
			//write to the file
			if (_MapView)
			{
				memcpy((unsigned char*)_MapView + bytes, data + bytes, 1);
			}
		}
		
	}
	bool BackupFSBitmap::IsSet(LONGLONG offset)
	{
		LONGLONG bytes = 0;
		LONGLONG bits = 0;
		bytes = offset / (_BlockSize * 8);
		bits = (offset % (_BlockSize * 8)) / _BlockSize;
		if (bytes >= _Length)
		{
			return false;
		}
		return _IsSet(_Data.data()[bytes], (unsigned int)bits);
	}
}